#include "linux/module.h"
#include <linux/device.h>
#include <linux/init.h>

#include <linux/fs.h>

#include <linux/kernel.h>

#include "linux/slab.h"

#include <asm/uaccess.h>

#include <linux/errno.h>

#define DevName "test_dev"

#define ClassName "class_test"



struct class    *mem_class;

struct Pci_dev  *test_devices;

struct cdev     _cdev;

dev_t    dev;

unsigned int fs_major =0;

static char *data;

static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos);

static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos);

static int test_open(struct inode *inode, struct file *file);

static int test_release(struct inode *inode,struct file *file);

static struct file_operations chr_fops=

{
read:
    test_read,
write:
    test_write,
open:
    test_open,
release:
    test_release,
};

int init_module(void);

void cleanup_module(void);

static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos)

{

    int len;
	
    if(count<0)

        return -EINVAL;

    len = strlen(data);

    if(len < count)                          count = len;

  copy_to_user(buf,data,count+1);

    return count;

}

static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos)

{

    if(count < 0)                          return -EINVAL;

    kfree(data);

    data = (char *)kmalloc(sizeof(count+1),GFP_KERNEL);

    if(!data)                          return -ENOMEM;

    copy_from_user(data,buffer,count+1);

    return count;

}

static int test_open(struct inode *inode, struct file *file)

{

    data = (char*)kmalloc(sizeof(char) * 1024,GFP_KERNEL);
	if(!data)
	{
		return -ENOMEM;
	}
	memset(data,0,1024);

    printk("This is open\n");

    return 0;

}

static int test_release(struct inode *inode,struct file *file)

{

    if(data)
    {
	kfree(data);
	data = NULL;
    }



    printk("this is released\n");

    return 0;

}

int init_module(void)

{

/*    int res;
	dev_t dev = MKDEV(fs_major,0);
	if(fs_major)
	{
		res = register_chrdev_region(dev,1,"test_dev");
	}
	else
	{
		res = alloc_chrdev_region(&dev,0,1,"test_dev");
	}
    //res=register_chrdev(0,"fs",&chr_fops);

    if(res<0)

    {

        printk("can't get major name!\n");

        return res;

    }

    if(fs_major == 0)               
fs_major = res;

    return 0;
*/
int result = alloc_chrdev_region(&dev, 0, 2, DevName);

    if (result < 0)

    {

        printk("Err:failed in alloc_chrdev_region!\n");

        return result;

    }
	mem_class = class_create(THIS_MODULE,ClassName);// /dev/ create devfile 

        if (IS_ERR(mem_class))

        {

        printk("Err:failed in creating class!\n");

    }
	device_create(NULL,dev,NULL,DevName);


    cdev_init(&_cdev,&test_fops);

    _cdev.owner = THIS_MODev.ops = &test_fops;
	result = cdev_add(&_cdev,dev,1);

    return result;
}

void cleanup_module(void)

{

    unregister_chrdev(fs_major,"fs");

}
